<?php

namespace app\service;

use Swoole\Http\Server;

/**
 * Class HttpServer
 * @property-read Server $_server
 */
class HttpServer
{
    /**
     * @var Server
     */
    protected $_server;

    /**
     * @var array
     */
    protected $_config;

    /**
     * @var array
     */
    protected $_route;

    /**
     * @param bool $daemonize
     */
    public function __construct(bool $daemonize)
    {
        $this->init();

        $this->_config['settings']['daemonize'] = $daemonize;

        $this->_server = new Server($this->_config['host'], $this->_config['port'],SWOOLE_PROCESS,$this->_config['sock_type']);

        $this->_server->set($this->_config['settings']);

        $this->_server->on('Start', [$this, 'onStart']);

        $this->_server->on('WorkerStart', [$this, 'onWorkerStart']);

        $this->_server->on('request', [$this, 'onRequest']);
    }

    /**
     * init
     */
    protected function init()
    {
        $this->_config = array_merge([
            'host' => '0.0.0.0',
            'port' => 9501,
            'sock_type' => SWOOLE_SOCK_TCP,
            'settings' => [
                'max_request'     => 1000,
                'daemonize'       => false,
                'log_file'        => null,
                'log_date_format' => '%Y-%m-%d %H:%M:%S',//设置 Server 日志时间格式，格式参考 strftime 的 format
            ]
        ],Config::getInstance()->get('app'));

        $this->_route = Config::getInstance()->get('routes');
    }

    /**
     * onStart
     * @param Server $server
     */
    public function onStart(Server $server)
    {
        is_linux() && cli_set_process_title('SwooleServer');
    }

    /**
     * onWorkerStart
     * @param Server $server
     * @param int $worker_id
     */
    public function onWorkerStart(Server $server, int $worker_id)
    {
        is_linux() && cli_set_process_title('SwooleWork_'.$worker_id);
    }

    /**
     * onRequest
     * @param \Swoole\Http\Request  $request
     * @param \Swoole\Http\Response $response
     */
    public function onRequest($request, $response)
    {
        $url = trim($request->server['request_uri'] ?? '/', '/');

        if(empty($url)){
            $url = '/';
        }

        if(empty($this->_route[$url])){
            $response->status(404);
            Log::warning('404 NOT FOUND.',$request);
        }else{
            try {
                [$controller,$action] = $this->_route[$url];

                $class = (new $controller(new Request($request), new Response($response)));
                if(!$class instanceof Controller){
                    throw new \Exception($class.' must be extends '.Controller::class);
                }
                return $class->{$action}();
            }catch (\Throwable $e){
                exception_format($e);
                $response->status(500);
                $response->end();
            }
        }
    }

    /**
     * getServer
     * @return Server
     */
    public function getServer(): Server
    {
        return $this->_server;
    }

    /**
     * on
     * @param $event_name
     * @param callable $callback
     */
    public function on($event_name, callable $callback)
    {
        $this->_server->on($event_name, $callback);
    }

    /**
     * start
     */
    public function start()
    {
        print_success('lnmp web is running.');
        print_success("http server url：http://{$this->_config['host']}:{$this->_config['port']}");
        $this->_server->start();
    }

}